﻿using Exceptionless;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ynzp.Core.AspNet;
using Ynzp.Core.Exceptions;

namespace ExceptionlessDemo.Filter
{
    /// <summary>
    /// 全局异常中间件，基于约定的方式来创建。默认是以Singleton的方式注册
    /// </summary>
    public class GlobalExceptionMiddleware
    {
        private readonly RequestDelegate next;
        //private ILogger<GlobalExceptionMiddleware> logger;
        private readonly IWebHostEnvironment _env;

        /// <summary>
        /// 构造函数，约定的第一个参数是RequestDelegate next，其它的可以根据需要进行注入
        /// 构造函数注入时，不应该注入非Singleton生命周期的服务
        /// </summary>
        /// <param name="next"></param>
        /// <param name="env"></param>
        public GlobalExceptionMiddleware(RequestDelegate next, IWebHostEnvironment env)
        {
            this.next = next;
            //this.logger = logger;
            _env = env;
        }

        /// <summary>
        /// 中间件的执行方法
        /// 约定的第一个参数是HttpContext context，其它的可以根据情况注入，注入的服务生命周期是Scope
        /// </summary>
        /// <param name="context"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context,ILogger<GlobalExceptionMiddleware> logger)
        {
            try
            {
                await next.Invoke(context);
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(context, ex);
            }
        }


        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            int code;
            string message;
            BizException bizException = null;
            //判断是不是BizException
            if (exception is BizException)
            {
                bizException = (BizException)exception;
            }
            else if (exception.InnerException is BizException)
            {
                bizException = (BizException)exception.InnerException;
            }
            //设置Code和Message,生产环境和非生产环境不同
            if (_env.IsProduction())
            {
                if (bizException != null)
                {
                    code = bizException.ErrCode;
                    message = bizException.ShowMsg;
                }
                else
                {
                    code = ResultCodes.Status500InternalServerError.ToInt32();
                    message = exception.Message;
                }
            }
            else
            {
                if (bizException != null)
                {
                    code = bizException.ErrCode;
                    message = bizException.Message;
                }
                else
                {
                    code = ResultCodes.Status500InternalServerError.ToInt32();
                    message = exception.Message;
                }
            }

            //返回客户端格式化的异常数据
            var data = ApiResult.NotOk(code, message);
            //输出的内容和返回码
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = code;
            //输出Json
            string result = JsonConvert.SerializeObject(data);
            await context.Response.WriteAsync(result, Encoding.UTF8);

            //记录日志
            await WriteRequestToLogAsync(context, exception);
        }

        private async Task WriteRequestToLogAsync(HttpContext context, Exception exception)
        {
            SortedDictionary<string, object> _data = new SortedDictionary<string, object>();

            //记录请求头
            HttpRequest request = context.Request;
            _data.Add("Url", request.Path.ToString());
            _data.Add("Headers", request.Headers.ToDictionary(x => x.Key, v => string.Join(";", v.Value.ToList())));
            _data.Add("Method", request.Method);
            //_data.Add("request.executeStartTime", DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));

            // 获取请求body内容
            var body = await HttpRequestHelper.ReadBodyAsync(request);
            _data.Add("Body", body);

            //提交到Exceptionless
            exception
               .ToExceptionless()
               // 设置一个ReferenceId方便查找
               .SetReferenceId(Guid.NewGuid().ToString("N"))
               .SetProperty("请求详情", _data)
               .Submit();
            //logger.LogError(exception,"",_data);
        }
    }
}
